#include <cassert>
#include <ctime>
#include <iostream>

#include "PreyStates.h"
#include "Entity/EntityManager.h"
#include "Entity/Game/Predator.h"
#include "Message/MessageDispatcher.h"


//! PreyStateWander
PreyStateWander* PreyStateWander::GetInstance()
{
	static PreyStateWander instance;
	return &instance;
}

void PreyStateWander::Enter(Prey* p)
{
	std::cout << p->GetEnityName() << "<PreyStateWander::Enter>: Began Wander\n";
}

void PreyStateWander::Execute(Prey* p)
{
}

void PreyStateWander::Exit(Prey* p)
{
	std::cout << p->GetEnityName() << "<PreyStateWander::Exit>: Message Received: Finished Wander\n";
}

bool PreyStateWander::OnMessage(Prey* p, const Message& m)
{
	std::cout << p->GetEnityName() << "<PreyStateWander::OnMessage>: Message Received\n";

	if (m.m_message == AITypes::DETECTED_BY_PREDATOR)
	{
		p->GetStateMachine()->ChangeCurrentState(PreyStateEvade::GetInstance());
		p->SetCurrentPredatorID(m.m_sender);
	}

	return true;
}


//! PreyStateEvade
PreyStateEvade* PreyStateEvade::GetInstance()
{
	static PreyStateEvade instance;
	return &instance;
}

void PreyStateEvade::Enter(Prey* p)
{
	std::cout << p->GetEnityName() << "<PreyStateEvade::Enter>: Began Evading\n";
}

void PreyStateEvade::Execute(Prey* p)
{
	srand((unsigned int)time(0));
	int r = rand() % 5 + 1;

	if (r == 1)
	{
		EntityManager& entityManager = EntityManager::GetInstance();
		BaseEntity* entity = entityManager.GetEntityFromID(p->GetCurrentPredatorID());

		Predator* predator = dynamic_cast<Predator*>(entity);

		assert(predator && "<PreyStateEvade::Execute>: Invalid predator ID");

		if (predator)
		{
			p->GetStateMachine()->ChangeCurrentState(PreyStateWander::GetInstance());
			
			//todo: should make this a typedef, enum or something
			p->SetCurrentPredatorID(-1);

			MessageDispatcher& messageDispatcher = MessageDispatcher::GetInstance();
			messageDispatcher.DispatchMessage(0, p->ID(), predator->ID(), AITypes::EVADED_PREDATOR, NULL);
		}

	}
}

void PreyStateEvade::Exit(Prey* p)
{
	std::cout << p->GetEnityName() << "<PreyStateEvade::Exit>: Message Received: Finished Evading\n";
}

bool PreyStateEvade::OnMessage(Prey* p, const Message& m)
{
	std::cout << p->GetEnityName() << "<PreyStateEvade::OnMessage>: Message Received\n";

	return true;
}